//
// Created by Yun Zeng on 2018/4/14.
//


#include "platform.h"
#include "platform_ht.h"
#include "platform_oled.h"
#include "platform_light.h"
#include "platform_infrared.h"

#include <linux/gpio.h>
#include "master.h"

#pragma pack(push)
#pragma pack(1)

typedef struct {
    uint8_t     type;
    uint16_t    len;
    uint8_t     data[0];
}platform_msg_typedef;

typedef struct {
    uint8_t     type;
    uint16_t    len;
    uint8_t     data[100];
}platform_recv_typedef;

#pragma pack(pop)

static platform_recv_typedef platform_recv;
DEFINE_SEMAPHORE(platform_recv_mutex);

// 温湿度读取返回结果
static int ht_recv(platform_ht_data_typedef *data);
static int light_recv(platform_light_data_typedef *data);

// HomeMaster 设备初始化
int platform_init(master_dev_typedef *dev) {
    // 设置GPIO18 GPIO19 引脚为GPIO模式
    // GPIO1_Mode: GPIO1 purpose selection
    // [31:30] PWM1_MODE 0b00: PWM ch1  0b01: GPIO -> GPIO18
    // [29:28] PWM0_MODE 0b00: PWM ch0  0b01: GPIO -> GPIO19
    uint32_t GPIO1_MODE = 0x10000060;
    //printk(MASTER_DEV_NAME ": infrared GPIO1_Mode Address(%08x) Value(%08x)\n", GPIO1_MODE, inl(GPIO1_MODE));
    outl((inl(GPIO1_MODE) & 0x00ffffff) | 0x50000400, GPIO1_MODE);
    //printk(MASTER_DEV_NAME ": infrared GPIO1_Mode Address(%08x) Value(%08x)\n", GPIO1_MODE, inl(GPIO1_MODE));

    platform_infrared_init(dev);
    platform_ht_init(ht_recv);
    platform_light_init(light_recv);
    platform_oled_init();

    memset(&platform_recv, 0x00, sizeof(platform_recv_typedef));
    sema_init(&platform_recv_mutex, 0);
    return 0;
}

int platform_exit(master_dev_typedef *dev) {
    platform_ht_exit();
    platform_infrared_exit(dev);
    platform_oled_exit();
    platform_light_exit();
    return 0;
}

// 设备数据读写
int32_t platform_read(uint8_t *data, uint16_t len) {
    int ret = down_interruptible(&platform_recv_mutex);
    if (ret == 0){
        uint16_t dl = (uint16_t) (platform_recv.len + 3);
        platform_recv.len = cpu_to_be16(platform_recv.len);
        memcpy(data, &platform_recv, dl);
        platform_recv.len = be16_to_cpu(platform_recv.len);
        //printk(MASTER_DEV_NAME ": recv(%02x) len(%d) ret(%d) \n", platform_recv.type, dl, ret);
        return dl;
    }
    return 0;
}

int32_t platform_write(uint8_t *data, uint16_t len) {
    int32_t result = 0;
    platform_msg_typedef *msg = (platform_msg_typedef *)data;
    msg->len = be16_to_cpu(msg->len);
    if (len != msg->len + sizeof(platform_msg_typedef)) {
        printk(MASTER_DEV_NAME ": msg format(%d:%d) err\n", len, msg->len);
        return -1;
    }

//    {
//        int i;
//        char log_buffer[msg->len * 2 + 1];
//        for (i=0; i<msg->len; i++) {
//            sprintf(&log_buffer[2*i], "%02x", msg->data[i]);
//        }
//        printk(MASTER_DEV_NAME ": msg(%02x) len(%d) data(%s)\n", msg->type, msg->len, log_buffer);
//    }

    else if (msg->type == MasterHTSensor) {
        platform_ht_write(msg->data, msg->len);
    }

    else if (msg->type == MasterOled) {
        platform_oled_write(msg->data, msg->len);
    }

    else if (msg->type == MasterLightSensor) {
        platform_light_write(msg->data, msg->len);
    }

    else if (msg->type == MasterInfrared) {
        platform_infrared_write(msg->data, msg->len);
    }

    msg->len = cpu_to_be16(msg->len);
    return result;
}

// 温湿度计读取数据
static int ht_recv(platform_ht_data_typedef *data) {
    platform_recv.type = MasterHTSensor;
    platform_recv.len = sizeof(platform_ht_data_typedef);
    memcpy(platform_recv.data, data, sizeof(platform_ht_data_typedef));

    up(&platform_recv_mutex);
    return sizeof(platform_ht_data_typedef);
}

static int light_recv(platform_light_data_typedef *data) {
    platform_recv.type = MasterLightSensor;
    platform_recv.len = sizeof(platform_light_data_typedef);
    memcpy(platform_recv.data, data, sizeof(platform_light_data_typedef));
    up(&platform_recv_mutex);
    return sizeof(platform_light_data_typedef);
}

int platform_open(void) {
    return 0;
}

int platform_close(void) {
    return 0;
}

